// 封装exceljs
const ExcelJS = require('exceljs');
const FileSaver = require('file-saver');
/**
 * 导出数据到Excel方法
 * @param {Array[Object]} config.data 表格数据
 * @param {Array[String]} config.fields 字段列表
 * @param {Array[String]} config.headers excel表头列表[[]]，可以是多级表头[['A1'，'B1'],['A2'，'B2']]
 * @param {Array[Object]} config.merges 需要合并的单元格，需要考虑表头的行数[{row:1, col:1, rowspan: 1, colspan: 2}]
 * @param {Array[Object]} config.attrs 单元格样式配置
 * @param {Array[Object]} config.views 工作表视图配置
 * @param {Array[Number]} config.columnsWidth 每个字段列对应的宽度
 * @param {Object} config.protect 工作表保护【此配置会保护全表，一般推荐只针对单元格进行保护配置】
 * @param {String} config.sheetName 工作表名称，默认从sheet1开始
 * @param {String} fileName excel文件名称
 */
export function exportDataToExcel(config, fileName) {
	if (!config) return;
	const options = {
		fileName: fileName || `导出excel文件【${Date.now()}】.xlsx`,
		worksheets: []
	}
	if (!Array.isArray(config)) {
		config = [config]
	}
	config.forEach((item) => {
		// 深拷贝data【JSON.stringify有缺陷，可自行换成_.cloneDeep】
		const data = JSON.parse(JSON.stringify(item.data));
		const results = data.map(obj => {
			return item.fields.map(key => {
				return obj[key]
			})
		})
		// 生成完整excel数据
		let excelData = [];
		excelData = excelData.concat(item.headers).concat(results);
		// 单元格合并处理【excel数据的第一行/列是从1开始】
		let excelMerges = [];
		excelMerges = item.merges.map(m => {
			return [m.row + 1, m.col + 1, m.row + m.rowspan, m.col + m.colspan]
		})
		// 单元格配置处理【excel数据的第一行/列是从1开始】
		let excelAttrs = [];
		excelAttrs = item.attrs.map(attr => {
			attr.rowStart += 1;
			attr.rowEnd += 1;
			attr.colStart += 1;
			attr.colEnd += 1;
			return attr
		})
		options.worksheets.push({
			data: excelData,
			merges: excelMerges,
			attrs: excelAttrs,
			views: item.views,
			columnsWidth: item.columnsWidth,
			protect: item.protect,
			sheetName: item.sheetName
		})
	})
	createExcel(options)
}
// 创建Excel文件方法
async function createExcel(options) {
	if (!options.worksheets.length) return;
	// 创建工作簿
	const workbook = new ExcelJS.Workbook();
	for (let i = 0; i < options.worksheets.length; i++) {
		const sheetOption = options.worksheets[i];
		// 创建工作表
		const sheet = workbook.addWorksheet(sheetOption.sheetName || 'sheet' + (i + 1));
		// 添加数据行
		sheet.addRows(sheetOption.data);
		// 配置视图
		sheet.views = sheetOption.views;
		// 单元格合并处理【开始行，开始列，结束行，结束列】
		if (sheetOption.merges) {
			sheetOption.merges.forEach((item) => {
				sheet.mergeCells(item);
			});
		}
		// 工作表保护
		if (sheetOption.protect) {
			const res = await sheet.protect(sheetOption.protect.password, sheetOption.protect.options);
		}
		// 单元格样式处理
		if (sheetOption.attrs.length) {
			sheetOption.attrs.forEach((item) => {
				const attr = item.attr || {};
				// 获取开始行-结束行; 开始列-结束列
				const rowStart = item.rowStart;
				const rowEnd = item.rowEnd;
				const colStart = item.colStart;
				const colEnd = item.colEnd;
				if (rowStart) { // 设置行
					for (let r = rowStart; r <= rowEnd; r++) {
						// 获取当前行
						const row = sheet.getRow(r);
						if (!!attr.height) {
							row.height = attr.height;
						}
						if (colStart) { // 列设置
							for (let c = colStart; c <= colEnd; c++) {
								// 获取当前单元格
								const cell = row.getCell(c);
								Object.keys(attr).forEach((key) => {
									// 给当前单元格设置定义的样式
									cell[key] = attr[key];
								});
							}
						} else {
							// 未设置列，整行设置【大纲级别】
							Object.keys(attr).forEach((key) => {
								row[key] = attr[key];
							});
						}
					}
				} else if (colStart) { // 未设置行，只设置了列
					for (let c = colStart; c <= colEnd; c++) {
						// 获取当前列，整列设置【大纲级别】
						const column = sheet.getColumn(c);
						Object.keys(attr).forEach((key) => {
							column[key] = attr[key];
						});
					}
				} else {
					// 没有设置具体的行列，则为整表设置
					Object.keys(attr).forEach((key) => {
						sheet[key] = attr[key];
					});
				}
			})
		}
		// 列宽设置
		if (sheetOption.columnsWidth) {
			for (let i = 0; i < sheet.columns.length; i++) {
				sheet.columns[i].width = sheetOption.columnsWidth[i]
			}
		}
	}
	// 生成excel文件
	workbook.xlsx.writeBuffer().then(buffer => {
		// application/octet-stream 二进制数据
		FileSaver.saveAs(new Blob([buffer], {
			type: 'application/octet-stream'
		}), options.fileName)
	})
}